package com.niiwoo.civet.trade.service.local.invest;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.activity.stage.service.prize.ActivityPrizeDubboService;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.request.InvestOrderListRequestDTO;
import com.niiwoo.civet.trade.dto.request.myloan.MyloanRequestDTO;
import com.niiwoo.civet.trade.dto.response.InvestOrderListResponseDTO;
import com.niiwoo.civet.trade.dto.response.InvestOrderReceivePaymentDetailDTO;
import com.niiwoo.civet.trade.dto.response.InvestOrderReceivePaymentPlanDTO;
import com.niiwoo.civet.trade.dto.response.ReceivableDetailResponseDTO;
import com.niiwoo.civet.trade.dto.response.myloan.inner.BackToArticleDetails;
import com.niiwoo.civet.trade.enums.*;
import com.niiwoo.civet.trade.service.local.refund.CommonLocalService;
import com.niiwoo.civet.trade.utils.RepaymentUtil;
import com.niiwoo.tripod.base.utils.DateUtils;
import com.niiwoo.tripod.provider.dto.response.PageResponseDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.FastDateFormat;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.support.Assert;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

import static com.niiwoo.tripod.base.utils.DateUtils.SHOW_DATE_FORMAT;

/**
 * 订单详情-回款计划
 * Created by zhangwanli on 2018/5/16.
 */
@Slf4j
@Service
public class ReceivePaymentPlanService {

    @Reference(version = "1.0.0")
    private ActivityPrizeDubboService activityPrizeDubboService;

    @Autowired
    private ProjectMapperExt projectMapperExt;
    @Autowired
    private ProjectInvestorPlanMapperExt projectInvestorPlanMapperExt;
    @Autowired
    private ProjectInvestOrderMapperExt projectInvestOrderMapperExt;
    @Autowired
    private ProjectContractMapperExt projectContractMapperExt;
    @Autowired
    private CommonLocalService commonLocalService;
    @Autowired
    private InvestOrderService investOrderService;
    @Autowired
    private ProjectPackageInvestOrderDetailMapperExt projectPackageInvestOrderDetailMapperExt;
    @Autowired
    private ProjectPackageInvestOrderMapperExt projectPackageInvestOrderMapperExt;


    /**
     * 订单详情-回款计划列表查询
     *
     * @param investOrderId 订单ID
     * @return InvestOrderReceivePaymentPlanDTO
     */
    public List<InvestOrderReceivePaymentPlanDTO> receivePaymentPlanList(Long investOrderId) {
        log.info("ReceivePaymentPlanService.receivePaymentPlanList:investOrderId={}", investOrderId);

        List<InvestOrderReceivePaymentPlanDTO> paymentPlanDTOList = new ArrayList<>();
        List<ProjectInvestorPlan> planList = projectInvestorPlanMapperExt.listByInvestOrder(investOrderId);
        ProjectInvestOrder projectInvestOrder = projectInvestOrderMapperExt.selectByPrimaryKey(investOrderId);
        Project project = projectMapperExt.selectByPrimaryKey(projectInvestOrder.getProjectId());
        Assert.notNull(projectInvestOrder, "projectInvestOrder is not null, investOrderId:" + investOrderId);

        // 提前结清期数、金额计算、已转让期数、金额计算
        Integer clearingPeriodNumber = this.getClearingOrTransfersPeriod(planList, InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE);
        BigDecimal clearingPeriodAmount = this.getClearingOrTransfersAmount(planList, InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE);
        Integer transfersPeriodNumber = this.getClearingOrTransfersPeriod(planList, InvestorPlanReceivedStatusEnum.TRANSFERRED);
        BigDecimal transfersReceiveAmount = this.getClearingOrTransfersAmount(planList, InvestorPlanReceivedStatusEnum.TRANSFERRED);

        for (ProjectInvestorPlan plan : planList) {
            InvestOrderReceivePaymentPlanDTO paymentPlanDTO = new InvestOrderReceivePaymentPlanDTO();
            paymentPlanDTO.setPlanId(plan.getId());
            paymentPlanDTO.setPeriodNum(plan.getCurrentPeriod());
            paymentPlanDTO.setReceiveDate(plan.getReceivedDate());
            paymentPlanDTO.setInvestOrderId(plan.getInvestOrderId());
            paymentPlanDTO.setReturnStatus(plan.getReceivedStatus());

            // 预计回款金额=当期应收本金+当期应收利息+当期应收加息
            paymentPlanDTO.setDueAmount(plan.getCapital().add(plan.getInterest()));
            // 已回金额=已回本金+已回利息+已回加息+已回罚
            paymentPlanDTO.setReceivedAmount(plan.getReceivedCapital().add(plan.getReceivedInterest()).add(plan.getReceivedPenaltyFee()));
            // 回款说明展示状态：0不显示，1显示已回款，2显示在第几期提前结清，3显示在第几期转让
            if(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode().equals(plan.getReceivedStatus())){
                paymentPlanDTO.setReceiveDisplayStatus(Byte.valueOf("0"));

                if(!paymentPlanDTO.getReceivedAmount().equals(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN))){
                    paymentPlanDTO.setReceiveDisplayStatus(Byte.valueOf("1"));
                }
            }else {
                paymentPlanDTO.setReceiveDisplayStatus(Byte.valueOf("1"));
            }

            // 已提前结清期数、金额处理
            if (clearingPeriodNumber != null && plan.getCurrentPeriod() > (clearingPeriodNumber - 1) && plan.getTotalPeriod() != 1) {
                paymentPlanDTO.setClearingPeriodNumber(clearingPeriodNumber - 1);
                paymentPlanDTO.setReceiveDisplayStatus(Byte.valueOf("2"));
                paymentPlanDTO.setReceivedAmount(plan.getCapital());
            }
            if(clearingPeriodNumber != null && plan.getCurrentPeriod() == (clearingPeriodNumber - 1) && plan.getTotalPeriod() != 1){
                paymentPlanDTO.setReceivedAmount(clearingPeriodAmount.add(plan.getReceivedCapital().add(plan.getReceivedInterest().add(plan.getReceivedPenaltyFee()))));
            }

            // 已转让期数、金额处理
            if (transfersPeriodNumber != null && plan.getCurrentPeriod() > transfersPeriodNumber  && plan.getTotalPeriod() != 1) {
                paymentPlanDTO.setNumberOfTransfers(transfersPeriodNumber);
                paymentPlanDTO.setReceiveDisplayStatus(Byte.valueOf("3"));
                paymentPlanDTO.setReceivedAmount(plan.getCapital());
            }
            if(transfersPeriodNumber != null && transfersPeriodNumber.equals(plan.getCurrentPeriod())  && plan.getTotalPeriod() != 1){
                paymentPlanDTO.setReceivedAmount(transfersReceiveAmount);
            }

            // 转让中和提前结清都为提前回款
            if (InvestorPlanReceivedStatusEnum.TRANSFERRED.getCode().equals(plan.getReceivedStatus())
                    || InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE.getCode().equals(plan.getReceivedStatus())) {
                paymentPlanDTO.setReturnStatus(InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE.getCode());
            }
            // 正常收款并且结清时间小于回款时间,则为提前回款
            if (InvestorPlanReceivedStatusEnum.NORMAL_RECEIVE.getCode().equals(plan.getReceivedStatus())){
                Date overTime = DateUtils.parseDateFromString(FastDateFormat.getInstance(SHOW_DATE_FORMAT).format(plan.getOverTime()), SHOW_DATE_FORMAT);
                if(overTime.before(plan.getReceivedDate())){
                    paymentPlanDTO.setReturnStatus(InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE.getCode());
                }
            }

            // 预计回款金额计算加息 : 不为已转让
           if(!InvestorPlanReceivedStatusEnum.TRANSFERRED.getCode().equals(plan.getReceivedStatus())){
                paymentPlanDTO.setDueAmount(paymentPlanDTO.getDueAmount().add(investOrderService.getPrizeCurrentPeriodAddInterest(projectInvestOrder, plan.getCurrentPeriod())));
                paymentPlanDTO.setDueAmount(paymentPlanDTO.getDueAmount().add(investOrderService.getProjectActivityCurrentPeriodAddInterest(project.getActivityRaiseRate(), projectInvestOrder.getId(), plan.getCurrentPeriod())));
               // 包加息
               if(Byte.valueOf("3").equals(projectInvestOrder.getInvestType())) {
                   ProjectPackageInvestOrderDetail investOrderDetail = projectPackageInvestOrderDetailMapperExt.selectByInvestOrderId(investOrderId);
                   if(investOrderDetail != null){
                       ProjectPackageInvestOrder packageInvestOrder = projectPackageInvestOrderMapperExt.selectByPrimaryKey(investOrderDetail.getPackageInvestOrderId());
                       if(packageInvestOrder != null){
                           paymentPlanDTO.setDueAmount(paymentPlanDTO.getDueAmount().add(investOrderService.getProjectActivityCurrentPeriodAddInterest(packageInvestOrder.getActivityRaiseRate(), projectInvestOrder.getId(), plan.getCurrentPeriod())));

                       }
                   }
               }
            }
            // 已回金额计算加息：正常收款、逾期收款
            if(plan.getReceivedInterest().compareTo(BigDecimal.ZERO) > 0
                    || InvestorPlanReceivedStatusEnum.NORMAL_RECEIVE.getCode().equals(plan.getReceivedStatus())
                    || InvestorPlanReceivedStatusEnum.OVERDUE_RECEIVE.getCode().equals(plan.getReceivedStatus())
                    || (InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE.getCode().equals(plan.getReceivedStatus()) && plan.getTotalPeriod() == 1)){
                paymentPlanDTO.setReceivedAmount(paymentPlanDTO.getReceivedAmount().add(investOrderService.getPrizeCurrentPeriodAddInterest(projectInvestOrder, plan.getCurrentPeriod())));
                paymentPlanDTO.setReceivedAmount(paymentPlanDTO.getReceivedAmount().add(investOrderService.getProjectActivityCurrentPeriodAddInterest(project.getActivityRaiseRate(), projectInvestOrder.getId(), plan.getCurrentPeriod())));
                // 包加息
                if(Byte.valueOf("3").equals(projectInvestOrder.getInvestType())) {
                    ProjectPackageInvestOrderDetail investOrderDetail = projectPackageInvestOrderDetailMapperExt.selectByInvestOrderId(investOrderId);
                    if(investOrderDetail != null){
                        ProjectPackageInvestOrder packageInvestOrder = projectPackageInvestOrderMapperExt.selectByPrimaryKey(investOrderDetail.getPackageInvestOrderId());
                        if(packageInvestOrder != null){
                            paymentPlanDTO.setReceivedAmount(paymentPlanDTO.getReceivedAmount().add(investOrderService.getProjectActivityCurrentPeriodAddInterest(packageInvestOrder.getActivityRaiseRate(), projectInvestOrder.getId(), plan.getCurrentPeriod())));
                        }
                    }
                }
            }
            paymentPlanDTOList.add(paymentPlanDTO);
        }
        return paymentPlanDTOList;
    }

    /**
     * 订单详情-单期回款计划详情查询
     *
     * @param investOrderId 订单ID
     * @param planId        回款计划ID
     * @return InvestOrderReceivePaymentDetailDTO
     */
    public InvestOrderReceivePaymentDetailDTO receivePaymentPlanDetail(Long investOrderId, Long planId) {
        log.info("ReceivePaymentPlanService.receivePaymentPlanDetail:investOrderId={}, planId={}", investOrderId, planId);

        InvestOrderReceivePaymentDetailDTO paymentDetailDTO = new InvestOrderReceivePaymentDetailDTO();
        ProjectInvestorPlan projectInvestPlan = projectInvestorPlanMapperExt.selectByPrimaryKey(planId);
        ProjectInvestOrder projectInvestOrder = projectInvestOrderMapperExt.selectByPrimaryKey(investOrderId);
        Project project = projectMapperExt.selectByPrimaryKey(projectInvestOrder.getProjectId());

        // 加息券加息
        BigDecimal addInterest = investOrderService.getPrizeCurrentPeriodAddInterest(projectInvestOrder, projectInvestPlan.getCurrentPeriod());
        // 标的加息
        addInterest = addInterest.add(investOrderService.getProjectActivityCurrentPeriodAddInterest(project.getActivityRaiseRate(), projectInvestOrder.getId(), projectInvestPlan.getCurrentPeriod()));
        // 包加息
        if(Byte.valueOf("3").equals(projectInvestOrder.getInvestType())) {
            ProjectPackageInvestOrderDetail investOrderDetail = projectPackageInvestOrderDetailMapperExt.selectByInvestOrderId(investOrderId);
            if(investOrderDetail != null){
                ProjectPackageInvestOrder packageInvestOrder = projectPackageInvestOrderMapperExt.selectByPrimaryKey(investOrderDetail.getPackageInvestOrderId());
                if(packageInvestOrder != null){
                    addInterest = addInterest.add(investOrderService.getProjectActivityCurrentPeriodAddInterest(packageInvestOrder.getActivityRaiseRate(), projectInvestOrder.getId(), projectInvestPlan.getCurrentPeriod()));
                }
            }
        }

        paymentDetailDTO.setInvestOrderId(investOrderId);
        paymentDetailDTO.setPeriodNum(projectInvestPlan.getCurrentPeriod());
        paymentDetailDTO.setReceivedStatus(this.receivePaymentStatus(projectInvestPlan));
        paymentDetailDTO.setExpectReceiveDate(projectInvestPlan.getReceivedDate());
        paymentDetailDTO.setInterestEndDate(projectInvestPlan.getReceivedDate());
        // 随机随还的提前结清，计息结束日期为结清日期
        if(OrgConstant.JUNTUO_ORG_ID.equals(project.getOrgId())
                && PeriodUnitEnum.DAY.getValue().equals(project.getDeadlineUnit())
                && InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())){
            paymentDetailDTO.setInterestEndDate(projectInvestPlan.getOverCurrentDate() == null ? projectInvestPlan.getOverTime() : projectInvestPlan.getOverCurrentDate());
        }

        // 待收明细
        InvestOrderReceivePaymentDetailDTO.AmountDetail dueDetail = new InvestOrderReceivePaymentDetailDTO.AmountDetail();
        dueDetail.setCapital(projectInvestPlan.getCapital().subtract(projectInvestPlan.getReceivedCapital()));
        dueDetail.setInterest(projectInvestPlan.getInterest().subtract(projectInvestPlan.getReceivedInterest()));
        dueDetail.setAddInterest(addInterest);
        dueDetail.setPenaltyFee(BigDecimal.ZERO);

        // 已收明细
        InvestOrderReceivePaymentDetailDTO.AmountDetail receivedDetail = new InvestOrderReceivePaymentDetailDTO.AmountDetail();
        receivedDetail.setCapital(projectInvestPlan.getReceivedCapital());
        receivedDetail.setInterest(projectInvestPlan.getReceivedInterest());
        receivedDetail.setAddInterest(BigDecimal.ZERO);
        receivedDetail.setPenaltyFee(projectInvestPlan.getReceivedPenaltyFee());

        if(InvestorPlanReceivedStatusEnum.OVERDUE_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())){
            paymentDetailDTO.setPenaltyFeeBeginDate(new DateTime(projectInvestPlan.getReceivedDate()).plusDays(1).toDate());
            paymentDetailDTO.setPenaltyFeeEndDate(projectInvestPlan.getOverTime());
        }
        if (InvestorPlanReceivedStatusEnum.NORMAL_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())
                || InvestorPlanReceivedStatusEnum.OVERDUE_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())
                || projectInvestPlan.getReceivedInterest().compareTo(BigDecimal.ZERO) > 0) {
            receivedDetail.setAddInterest(addInterest);
        }

        // 预计回款金额=当期应收本金+当期应收利息+当期应收加息
        if(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())){
            paymentDetailDTO.setTotalAmount(projectInvestPlan.getCapital().add(projectInvestPlan.getInterest())
                    .subtract(projectInvestPlan.getReceivedCapital()).subtract(projectInvestPlan.getReceivedInterest()));
            if(projectInvestPlan.getReceivedInterest().compareTo(BigDecimal.ZERO) <= 0){
                paymentDetailDTO.setTotalAmount(paymentDetailDTO.getTotalAmount().add(addInterest));
            }
        }else {
            paymentDetailDTO.setTotalAmount(projectInvestPlan.getReceivedCapital().add(projectInvestPlan.getReceivedInterest()).add(projectInvestPlan.getReceivedPenaltyFee()));
            if(InvestorPlanReceivedStatusEnum.NORMAL_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())
                    || InvestorPlanReceivedStatusEnum.OVERDUE_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())){
                paymentDetailDTO.setTotalAmount(paymentDetailDTO.getTotalAmount().add(addInterest));
            }
        }

        //  如果本金利息已收，状态为未结清。罚息未收完。前端需要展示待收罚息
        if(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())
                && projectInvestPlan.getReceivedCapital().compareTo(projectInvestPlan.getCapital()) == 0
                && projectInvestPlan.getReceivedInterest().compareTo(projectInvestPlan.getInterest()) == 0
                && projectInvestPlan.getReceivedPenaltyFee().compareTo(projectInvestPlan.getTotalPenaltyFee()) < 0 ){
            dueDetail.setPenaltyFee(projectInvestPlan.getTotalPenaltyFee().subtract(projectInvestPlan.getReceivedPenaltyFee()));
            paymentDetailDTO.setTotalAmount(paymentDetailDTO.getTotalAmount().add(projectInvestPlan.getTotalPenaltyFee()).subtract(projectInvestPlan.getReceivedPenaltyFee()));
        }

        // 实际回款日期 (如果结清时间为空，只要本金利息已经收款，回款日期赋值修改日期)
        if(projectInvestPlan.getOverTime() != null){
            paymentDetailDTO.setActualReceiveDate(projectInvestPlan.getOverTime());
        } else if(projectInvestPlan.getReceivedCapital().compareTo(projectInvestPlan.getCapital()) == 0
                && projectInvestPlan.getReceivedInterest().compareTo(projectInvestPlan.getInterest()) == 0){
            paymentDetailDTO.setActualReceiveDate(projectInvestPlan.getUpdateTime());
        }

        if(ReceivePaymentStatusEnum.NORMAL_RECEIVE.getCode().equals(paymentDetailDTO.getReceivedStatus())){
            Date overTime = DateUtils.parseDateFromString(FastDateFormat.getInstance(SHOW_DATE_FORMAT).format(projectInvestPlan.getOverTime()), SHOW_DATE_FORMAT);;
            if(projectInvestPlan.getReceivedDate().before(overTime)){
                paymentDetailDTO.setActualReceiveDate(projectInvestPlan.getReceivedDate());
            }
        }

        // 计息开始日期
        if(projectInvestPlan.getCurrentPeriod() == 1){
            paymentDetailDTO.setInterestBeginDate(project.getFullSuccessTime());
        }else {
            Date interestBeginDate = projectInvestorPlanMapperExt.selectProjectIdReceivedDateByPeriod(projectInvestOrder.getProjectId(), projectInvestPlan.getCurrentPeriod() - 1);
            paymentDetailDTO.setInterestBeginDate(new DateTime(interestBeginDate).plusDays(1).toDate());
        }

        if(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())
                && projectInvestPlan.getReceivedDate().before(commonLocalService.getCurrentDate())
                && project.getAdvanceOverdueDays() != null){
            if(!(projectInvestPlan.getReceivedCapital().compareTo(projectInvestPlan.getCapital()) == 0
                    && projectInvestPlan.getReceivedInterest().compareTo(projectInvestPlan.getInterest()) == 0)) {
                if(project.getAdvanceOverdueDays() == 0) {
                    paymentDetailDTO.setAdvanceHints("担保公司将在24小时内代偿当期本息");
                }else {
                    paymentDetailDTO.setAdvanceHints("若借款人逾期" + project.getAdvanceOverdueDays() + "天，担保公司将在第" + (project.getAdvanceOverdueDays() + 1) + "天代偿当期本息");
                }
            }
        }
        if(InvestorPlanReceivedStatusEnum.OVERDUE_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())){
            if(projectInvestPlan.getIsGuarantee().equals(Byte.valueOf("1")) && project.getAdvanceOverdueDays() != null){
                if(project.getAdvanceOverdueDays() == 0) {
                    paymentDetailDTO.setAdvanceHints("借款人逾期，担保公司代偿当期本息");
                }else {
                    paymentDetailDTO.setOverdueDays(RepaymentUtil.getOverdueDay(projectInvestPlan.getReceivedDate(),
                            projectInvestPlan.getOverCurrentDate() != null ? projectInvestPlan.getOverCurrentDate() : projectInvestPlan.getOverTime()));
                    paymentDetailDTO.setAdvanceHints("借款人逾期" + paymentDetailDTO.getOverdueDays() + "天，担保公司代偿当期本息");
                }
            }else if(projectInvestPlan.getIsGuarantee().equals(Byte.valueOf("0"))){
                paymentDetailDTO.setOverdueDays(RepaymentUtil.getOverdueDay(projectInvestPlan.getReceivedDate(),
                        projectInvestPlan.getOverCurrentDate() != null ? projectInvestPlan.getOverCurrentDate() : projectInvestPlan.getOverTime()));
                paymentDetailDTO.setAdvanceHints("共逾期" + paymentDetailDTO.getOverdueDays() + "天，借款人已还款");
            }
        }

        // 结清、转让期数、金额计算
        BigDecimal receiveAmount = BigDecimal.ZERO;
        List<ProjectInvestorPlan>  planList = projectInvestorPlanMapperExt.listByInvestOrder(investOrderId);
        Integer clearingPeriodNumber = this.getClearingOrTransfersPeriod(planList, InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE);
        Integer numberOfTransfers = this.getClearingOrTransfersPeriod(planList, InvestorPlanReceivedStatusEnum.TRANSFERRED);

        if(clearingPeriodNumber != null && projectInvestPlan.getCurrentPeriod() == (clearingPeriodNumber - 1)){
            receivedDetail.setCapital(BigDecimal.ZERO);
            receivedDetail.setInterest(BigDecimal.ZERO);
            paymentDetailDTO.setClearingPeriodNumber(clearingPeriodNumber - 1);
            for (ProjectInvestorPlan plan : planList) {
                if (plan.getCurrentPeriod() >= paymentDetailDTO.getClearingPeriodNumber()) {
                    receiveAmount = receiveAmount.add(plan.getReceivedCapital().add(plan.getReceivedInterest()).add(plan.getReceivedPenaltyFee()));
                    receivedDetail.setCapital(receivedDetail.getCapital().add(plan.getReceivedCapital()));
                    receivedDetail.setInterest(receivedDetail.getInterest().add(plan.getReceivedInterest()));
                }
            }
            receivedDetail.setAddInterest(addInterest);
            paymentDetailDTO.setTotalAmount(receiveAmount.add(receivedDetail.getAddInterest()));
        }
        if(numberOfTransfers != null && projectInvestPlan.getCurrentPeriod().equals(numberOfTransfers)){
            receivedDetail.setCapital(BigDecimal.ZERO);
            receivedDetail.setInterest(BigDecimal.ZERO);
            paymentDetailDTO.setNumberOfTransfers(this.getClearingOrTransfersPeriod(planList, InvestorPlanReceivedStatusEnum.TRANSFERRED));
            for (ProjectInvestorPlan plan : planList) {
                if (InvestorPlanReceivedStatusEnum.TRANSFERRED.getCode().equals(plan.getReceivedStatus())) {
                    receiveAmount = receiveAmount.add(plan.getReceivedCapital().add(plan.getReceivedInterest()).add(plan.getReceivedPenaltyFee()));
                    receivedDetail.setCapital(receivedDetail.getCapital().add(plan.getReceivedCapital()));
                    receivedDetail.setInterest(receivedDetail.getInterest().add(plan.getReceivedInterest()));
                }
            }
            paymentDetailDTO.setTotalAmount(receiveAmount);
        }

        if (addInterest != null && receivedDetail.getAddInterest() != null
                && !InvestorPlanReceivedStatusEnum.TRANSFERRED.getCode().equals(projectInvestPlan.getReceivedStatus())
                && !InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE.getCode().equals(projectInvestPlan.getReceivedStatus())) {
            dueDetail.setAddInterest(addInterest.subtract(receivedDetail.getAddInterest()));
        }
        paymentDetailDTO.setDueDetail(dueDetail);
        paymentDetailDTO.setReceivedDetail(receivedDetail);
        return paymentDetailDTO;
    }

    /**
     * 获取结清、转让期数
     * @return Integer
     */
    private Integer getClearingOrTransfersPeriod(List<ProjectInvestorPlan> planList, InvestorPlanReceivedStatusEnum statusEnum){
        for (ProjectInvestorPlan p : planList) {
            if (statusEnum.getCode().equals(p.getReceivedStatus())) {
                return p.getCurrentPeriod();
            }
        }
        return null;
    }

    /**
     * 获取结清、转让当期金额
     * @return Integer
     */
    private BigDecimal getClearingOrTransfersAmount(List<ProjectInvestorPlan> planList, InvestorPlanReceivedStatusEnum statusEnum){
        BigDecimal receiveAmount = BigDecimal.ZERO;
        for (ProjectInvestorPlan plan : planList) {
            if (statusEnum.getCode().equals(plan.getReceivedStatus())){
                receiveAmount = receiveAmount.add(plan.getReceivedCapital().add(plan.getReceivedInterest()).add(plan.getReceivedPenaltyFee()));
            }
        }
        return receiveAmount;
    }

    /**
     *  回款状态：1待回款，2按时回款，3逾期中，4逾期已收款，5提前回款，6已转让，7已提前结清, 8逾期部分回款
     * @return Byte
     */
    private Byte receivePaymentStatus(ProjectInvestorPlan plan){
        Byte receivedStatus = plan.getReceivedStatus();

        if(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode().equals(plan.getReceivedStatus())){
            BigDecimal receiveAmount = plan.getReceivedCapital().add(plan.getReceivedInterest().add(plan.getReceivedPenaltyFee()));
            Date currentTime = commonLocalService.getCurrentDate();
            if(currentTime.after(plan.getReceivedDate()) && receiveAmount.compareTo(BigDecimal.ZERO) == 0){
                return ReceivePaymentStatusEnum.OVERDUE.getCode();
            }else if(currentTime.after(plan.getReceivedDate()) && receiveAmount.compareTo(BigDecimal.ZERO) > 0){
                return ReceivePaymentStatusEnum.OVERDUE_PART_RECEIVE.getCode();
            }else{
                return ReceivePaymentStatusEnum.NON_RECEIVE.getCode();
            }
        }else if(InvestorPlanReceivedStatusEnum.NORMAL_RECEIVE.getCode().equals(plan.getReceivedStatus())){
            Date overTime = DateUtils.parseDateFromString(FastDateFormat.getInstance(SHOW_DATE_FORMAT).format(plan.getOverTime()), SHOW_DATE_FORMAT);
            if(overTime.before(plan.getReceivedDate())){
                return ReceivePaymentStatusEnum.EARLY_RECEIVE.getCode();
            }else {
                return ReceivePaymentStatusEnum.NORMAL_RECEIVE.getCode();
            }
        }else if(InvestorPlanReceivedStatusEnum.OVERDUE_RECEIVE.getCode().equals(plan.getReceivedStatus())){
            return ReceivePaymentStatusEnum.OVERDUE_RECEIVE.getCode();
        } else if(InvestorPlanReceivedStatusEnum.OVER_DEBT_RECEIVE.getCode().equals(plan.getReceivedStatus())){
            return ReceivePaymentStatusEnum.OVER_DEBT_RECEIVE.getCode();
        } else if(InvestorPlanReceivedStatusEnum.TRANSFERRED.getCode().equals(plan.getReceivedStatus())){
            return ReceivePaymentStatusEnum.TRANSFERRED.getCode();
        }
        return receivedStatus;
    }

    /**
     * PC投资订单
     * 投资订单衍变状态（0处理中，1投资中，2回款中，3回款逾期，4已关闭，5已结清，6转让中，7已转让）
     * type   订单类型-0进行中的投资，1已结束的投资
     * status 订单状态-0:全部，1正常回款，2已逾期，3投资中，4已结清，5已关闭
     * @return InvestOrderListResponseDTO
     */
    public PageResponseDTO<InvestOrderListResponseDTO> investOrderList(InvestOrderListRequestDTO requestDTO) {
        log.info("ReceivePaymentPlanService.investOrderList:requestDTO={}", requestDTO);
        if(requestDTO.getStatus() != null && requestDTO.getStatus() != 0){
            requestDTO.setStatus(InvestOrderStatusEnum.typeOf(requestDTO.getStatus()).getEvolutionStatusEnum().getValue());
        }

        InvestOrderListRequestDTO dto = new InvestOrderListRequestDTO();
        dto.setStatus(Byte.valueOf("0"));
        dto.setType(requestDTO.getType());
        dto.setUserId(requestDTO.getUserId());
        dto.setPageSize(99999);
        List<ProjectInvestOrder> allProjectInvestOrderList = projectInvestOrderMapperExt.selectOriginalInvestOrderList(dto);
        if(allProjectInvestOrderList.size() <= 0){
            return null;
        }

        List<InvestOrderListResponseDTO> list = new ArrayList<>();
        InvestOrderListResponseDTO responseDTO = new InvestOrderListResponseDTO();
        PageResponseDTO<InvestOrderListResponseDTO> result = new PageResponseDTO<>();
        responseDTO.setAllNum(allProjectInvestOrderList.size());
        allProjectInvestOrderList.forEach( p->{
            Byte evolutionStatus = ProjectInvestOrderEvolutionStatusEnum.getByValue(p.getEvolutionStatus()).getValue();
            if(ProjectInvestOrderEvolutionStatusEnum.INVESTING.getValue().byteValue() == evolutionStatus){
                responseDTO.setCollectingNum(responseDTO.getCollectingNum() + 1);
            }else if(ProjectInvestOrderEvolutionStatusEnum.BACKING.getValue().byteValue() == evolutionStatus){
                responseDTO.setNormalReceivingNum(responseDTO.getNormalReceivingNum() + 1);
            }else if(ProjectInvestOrderEvolutionStatusEnum.BACKING_OVERDUE.getValue().byteValue() == evolutionStatus){
                responseDTO.setOverdueNum(responseDTO.getOverdueNum() + 1);
            }else if(ProjectInvestOrderEvolutionStatusEnum.CLOSED.getValue().byteValue() == evolutionStatus){
                responseDTO.setCloseNum(responseDTO.getCloseNum() + 1);
            }else if(ProjectInvestOrderEvolutionStatusEnum.ALL_BACKED.getValue().byteValue() == evolutionStatus){
                responseDTO.setClearingNum(responseDTO.getClearingNum() + 1);
            }
        });

        Integer count = projectInvestOrderMapperExt.selectOriginalInvestOrderCount(requestDTO);
        result.setTotalCount(count);
        result.measureTotalPage(count, requestDTO.getPageSize());
        if (count <= 0) {
            list.add(responseDTO);
            result.setItems(list);
            return result;
        }

        List<ProjectInvestOrder> projectInvestOrderList = projectInvestOrderMapperExt.selectOriginalInvestOrderList(requestDTO);
        Set<Long> projectIds = new HashSet<>();
        Map<Long, ProjectContract> projectContractMap = new HashMap<>();
        projectInvestOrderList.forEach(p-> projectIds.add(p.getProjectId()));

        List<ProjectContract> contracts = projectContractMapperExt.queryFastLoanContractByProjectIdSet(projectIds);
        contracts.forEach(contract-> projectContractMap.put(contract.getProjectId(), contract));

        List<InvestOrderListResponseDTO.InvestOrderList> investOrderList = new ArrayList<>();
        for (ProjectInvestOrder projectInvestOrder : projectInvestOrderList) {
            InvestOrderListResponseDTO.InvestOrderList investOrder = new InvestOrderListResponseDTO.InvestOrderList();
            investOrder.setOrderId(projectInvestOrder.getId());
            investOrder.setProjectId(projectInvestOrder.getProjectId());
            investOrder.setContractAmount(projectInvestOrder.getAmount());
            investOrder.setBorrowRate(projectInvestOrder.getBorrowRate());
            investOrder.setDeadline(projectInvestOrder.getDeadline());
            investOrder.setDeadlineUnit(projectInvestOrder.getDeadlineUnit());
            investOrder.setInvestDate(projectInvestOrder.getCreateTime());
            if (projectContractMap.get(projectInvestOrder.getProjectId()) != null) {
                investOrder.setToViewContractUrl(projectContractMap.get(projectInvestOrder.getProjectId()).getViewUrl());
                investOrder.setDownloadContractUrl(projectContractMap.get(projectInvestOrder.getProjectId()).getDownloadUrl());
            }

            Byte evolutionStatus = ProjectInvestOrderEvolutionStatusEnum.getByValue(projectInvestOrder.getEvolutionStatus()).getValue();
            if(ProjectInvestOrderEvolutionStatusEnum.INVESTING.getValue().byteValue() == evolutionStatus){
                investOrder.setProjectStatus(InvestOrderStatusEnum.INVESTING.getType());
            }else if(ProjectInvestOrderEvolutionStatusEnum.BACKING.getValue().byteValue() == evolutionStatus){
                investOrder.setProjectStatus(InvestOrderStatusEnum.BACKING.getType());
            }else if(ProjectInvestOrderEvolutionStatusEnum.BACKING_OVERDUE.getValue().byteValue() == evolutionStatus){
                investOrder.setProjectStatus(InvestOrderStatusEnum.BACKING_OVERDUE.getType());
            }else if(ProjectInvestOrderEvolutionStatusEnum.CLOSED.getValue().byteValue() == evolutionStatus){
                investOrder.setProjectStatus(InvestOrderStatusEnum.CLOSED.getType());
            }else if(ProjectInvestOrderEvolutionStatusEnum.ALL_BACKED.getValue().byteValue() == evolutionStatus){
                investOrder.setProjectStatus(InvestOrderStatusEnum.ALL_BACKED.getType());
            }
            investOrderList.add(investOrder);
        }

        responseDTO.setList(investOrderList);
        list.add(responseDTO);
        result.setItems(list);
        log.info("ReceivePaymentPlanService.investOrderList:responseDTO={}", JSON.toJSON(responseDTO));
        return result;
    }

    /**
     * PC我的投资页-回款详情
     * 收款状态(1未收款，2正常收款，3逾期收款，4提前结清收款，5已转让)
     *
     * @param investOrderId 订单ID
     * @return ReceivableDetailResponseDTO
     */
    public ReceivableDetailResponseDTO receivableDetail(Long investOrderId) {
        log.info("ReceivePaymentPlanService.receivableDetail:investOrderId={}", investOrderId);
        List<ProjectInvestorPlan> planList = projectInvestorPlanMapperExt.listByInvestOrder(investOrderId);
        ProjectInvestOrder investOrder = projectInvestOrderMapperExt.selectByPrimaryKey(investOrderId);
        ReceivableDetailResponseDTO responseDTO = new ReceivableDetailResponseDTO();
        responseDTO.setInvestOrderId(investOrderId);
        responseDTO.setProjectId(investOrder.getProjectId());
        responseDTO.setTitle(investOrder.getTitle().replaceAll("借款用途：","").replaceAll("借款用于",""));
        responseDTO.setBorrowRate(investOrder.getBorrowRate());
        responseDTO.setRepaymentType(investOrder.getRepaymentType());
        responseDTO.setDeadline(investOrder.getDeadline());
        responseDTO.setDeadlineUnit(investOrder.getDeadlineUnit());
        List<ReceivableDetailResponseDTO.ReceivableList> receivableList = new ArrayList<>();
        planList.forEach(list -> {
            ReceivableDetailResponseDTO.ReceivableList receivable = new ReceivableDetailResponseDTO.ReceivableList();
            receivable.setReward(BigDecimal.ZERO);
            receivable.setCurrentPeriod(list.getCurrentPeriod());
            //回款状态：1已回款，2待回款
            if(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode().byteValue() != list.getReceivedStatus()){
                receivable.setReceivedStatus(Byte.valueOf("1"));
                receivable.setCapital(list.getReceivedCapital());
                receivable.setInterest(list.getReceivedInterest());
                receivable.setReceiveDate(list.getOverTime());
            }else {
                receivable.setReceivedStatus(Byte.valueOf("2"));
                receivable.setCapital(list.getCapital());
                receivable.setInterest(list.getInterest());
                receivable.setReceiveDate(list.getReceivedDate());
            }
            receivableList.add(receivable);
        });
        responseDTO.setList(receivableList);
        log.info("ReceivePaymentPlanService.receivableDetail:responseDTO={}", JSON.toJSON(responseDTO));
        return responseDTO;
    }

    /**
     * PC账户首页-回款日历
     *
     * @param requestDTO MyLoanRequestDTO
     * @return list BackToArticleDetails
     */
    public List<BackToArticleDetails> receivableCalendar(MyloanRequestDTO requestDTO) {

        return projectInvestorPlanMapperExt.queryReceivableListByDate(requestDTO);
    }

}
